package lucava.metamodel.java.visitor;

import java.util.Iterator;

import lucava.metamodel.dot.DotAssociation;
import lucava.metamodel.dot.DotGraph;
import lucava.metamodel.dot.DotNode;
import lucava.metamodel.dot.DotProperty;
import lucava.metamodel.java.Annotations;
import lucava.metamodel.java.Attribute;
import lucava.metamodel.java.Comments;
import lucava.metamodel.java.MetaClasse;
import lucava.metamodel.java.MetaClassifier;
import lucava.metamodel.java.MetaInterface;
import lucava.metamodel.java.MetaModel;
import lucava.metamodel.java.MetaPackage;
import lucava.metamodel.java.Methode;
import lucava.metamodel.java.MethodeBody;
import lucava.metamodel.java.MethodeSignature;
import lucava.metamodel.java.Modifier;
import lucava.metamodel.java.Parameter;
import lucava.metamodel.java.Variable;
import lucava.metamodel.java.Visibility;
import lucava.metamodel.java.type.MetaParametricType;
import lucava.metamodel.java.type.MetaType;

/**
 * Générateur d'un MetaModel DOT à partir d'un MetaModel Java.
 */
public class DotMetaModelGenerator implements IJavaMetaModelVisitor {

	/**
	 * Flux d'écriture courant.
	 */
	protected StringBuffer mCurrentStringBuffer;

	/**
	 * Graphe DOT généré.
	 */
	protected DotGraph mGeneratedGraph = new DotGraph();

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitVisibility(lucava.metamodel.java.Visibility)
	 */
	@Override
	public void visitVisibility(Visibility visibility) {

		// Si c'est un objet private
		if (visibility.isPrivate()) {
			this.mCurrentStringBuffer.append(" + ");
		} else

		// Si c'est un objet protected
		if (visibility.isProtected()) {
			this.mCurrentStringBuffer.append(" # ");
		} else

		// Si c'est un objet public
		if (visibility.isPublic()) {
			this.mCurrentStringBuffer.append(" - ");
		}
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitType(lucava.metamodel.java.type.MetaType)
	 */
	@Override
	public void visitType(MetaType metaType) {
		// Do nothing...

	}

	/**
	 * Génère le contenu du composant de l'Interface.
	 * 
	 * @param aMetaInterface
	 *            , Interface dont le contenu est à générer.
	 */
	protected void generateInterfaceContentComponent(
			MetaInterface aMetaInterface) {

		this.mCurrentStringBuffer.append("label=\"{ ");

		this.mCurrentStringBuffer.append(" \\<\\< Interface \\>\\> \\n");

		// Ajout de la visibilité de la classe
		aMetaInterface.getVisibility().accept(this);

		// Ajout du nom de la classe
		this.mCurrentStringBuffer.append(aMetaInterface.getName());

		// Ajout d'un séparateur
		this.mCurrentStringBuffer.append(" | ");

		// Ajout d'un séparateur
		this.mCurrentStringBuffer.append(" | ");

		// Ajout des méthodes de l'interface
		Iterator<MethodeSignature> signatureIt = aMetaInterface.getMethods()
				.iterator();
		while (signatureIt.hasNext()) {
			signatureIt.next().accept(this);

			// Ajout d'une ligne s'il reste des méthodes
			if (signatureIt.hasNext()) {
				this.mCurrentStringBuffer.append("\\n");
			}
		}

		this.mCurrentStringBuffer.append(" }\"");
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitInterface(lucava.metamodel.java.MetaInterface)
	 */
	@Override
	public void visitInterface(MetaInterface metaInterface) {

		// Création d'un noeud DOT pour l'interface
		DotNode interfaceNode = new DotNode();
		interfaceNode.setName(metaInterface.getName());

		// Ajout de la propriété à la l'interface (i.e. ses composants internes)

		// Création d'un nouveau StringBuffer pour le contenu du composant
		this.mCurrentStringBuffer = new StringBuffer("style=filled,fillcolor=gray95,shape=record,");

		// Génération du contenu du composant
		this.generateInterfaceContentComponent(metaInterface);

		// Ajout de la propriété au noeud
		DotProperty interfaceProperty = new DotProperty();
		interfaceProperty
				.setPropertyValue(this.mCurrentStringBuffer.toString());
		interfaceNode.getNodeProperties().add(interfaceProperty);

		// Vidage du buffer d'écriture
		this.mCurrentStringBuffer = new StringBuffer();

		// Ajout des éventuelles super-interfaces
		Iterator<MetaInterface> interfaceIt = metaInterface.getExtends()
				.iterator();
		while (interfaceIt.hasNext()) {
			// Ajout du lien entre l'interface et ses super-interfaces
			this.addExtendsAssociationBetween(interfaceNode, interfaceIt.next());
		}

		// Ajout de l'interface au graphe généré
		this.mGeneratedGraph.getNodes().add(interfaceNode);
	}

	/**
	 * Génère le contenu du composant de la Classe.
	 * 
	 * @param metaClasse
	 *            , Classe dont le contenu est à générer.
	 */
	protected void generateClassContentComponent(MetaClasse metaClasse) {

		this.mCurrentStringBuffer.append("label=\"{ ");

		// Si la classe est abstraite
		if (metaClasse.getModifier().isAbstract()) {
			this.mCurrentStringBuffer.append("\\<\\< Abstract \\>\\> \\n");
		}

		// Si la classe est static
		if (metaClasse.getModifier().isStatic()) {
			this.mCurrentStringBuffer.append("\\<\\< Static \\>\\> \\n");
		}

		// Ajout de la visibilité de la classe
		metaClasse.getVisibility().accept(this);

		// Ajout du nom de la classe
		this.mCurrentStringBuffer.append(metaClasse.getName());

		// Ajout d'un séparateur
		this.mCurrentStringBuffer.append(" | ");

		// Ajout des attributs de la classe
		Iterator<Attribute> attributeIt = metaClasse.getAttributes().iterator();
		while (attributeIt.hasNext()) {
			attributeIt.next().accept(this);

			// Ajout d'une ligne s'il reste des attributs
			if (attributeIt.hasNext()) {
				this.mCurrentStringBuffer.append("\\n");
			}
		}

		// Ajout d'un séparateur
		this.mCurrentStringBuffer.append(" | ");

		// Ajout des méthodes de la classe
		Iterator<Methode> methodeIt = metaClasse.getMethods().iterator();
		while (methodeIt.hasNext()) {
			methodeIt.next().accept(this);

			// Ajout d'une ligne s'il reste des méthodes
			if (methodeIt.hasNext()) {
				this.mCurrentStringBuffer.append("\\n");
			}
		}

		this.mCurrentStringBuffer.append(" }\"");
	}

	/**
	 * Construit une association entre un noeud de classe et un classifier
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe source de l'association.
	 * @param anAssociatedClassifier
	 *            , Classifier associé à la classe.
	 */
	protected DotAssociation createAssociationBetween(DotNode aClassNode,
			MetaClassifier anAssociatedClassifier) {

		// Création d'un noeud pour récupérer le nom de la classe liée
		DotNode linkedClassNode = new DotNode();
		linkedClassNode.setName(anAssociatedClassifier.getName());

		// Création de l'association entre la classe et sa classe liée
		DotAssociation association = new DotAssociation();
		association.setFromNode(aClassNode);
		association.setToNode(linkedClassNode);

		return association;
	}

	/**
	 * Construit une association entre un classifier et un noeud de classe.
	 * 
	 * * @param anAssociatedClassifier , Classifier source de l'association.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT associé au classifier
	 */
	protected DotAssociation createAssociationBetween(
			MetaClassifier anAssociatedClassifier, DotNode aClassNode) {

		// Création d'un noeud pour récupérer le nom du classifier source
		DotNode classifierNode = new DotNode();
		classifierNode.setName(anAssociatedClassifier.getName());

		// Création de l'association entre le classifier et sa classe liée
		DotAssociation association = new DotAssociation();
		association.setFromNode(classifierNode);
		association.setToNode(aClassNode);

		return association;
	}

	/**
	 * Ajoute une propriété à une association.
	 * 
	 * @param anAssociation
	 *            , Association à laquelle ajouter la propriété.
	 * @param aProperty
	 *            , Valeur de la propriété.
	 */
	protected void addPropertyToAssociation(DotAssociation anAssociation,
			String aProperty) {
		DotProperty associationProperty = new DotProperty();
		associationProperty.setPropertyValue(aProperty);
		anAssociation.getProperties().add(associationProperty);
	}

	/**
	 * Ajout une relation simple entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aLinkedClass
	 *            , Classe à lier.
	 * @param associationName
	 *            , Nom de l'association (ou null).
	 */
	protected void addSimpleAssociationBetween(DotNode aClassNode,
			MetaClasse aLinkedClass, String associationName) {

		// Création de l'association entre la classe et sa classe liée
		DotAssociation simpleAssociation = this.createAssociationBetween(
				aClassNode, aLinkedClass);

		// Ajout du style de la fleche de l'association.
		this.addPropertyToAssociation(simpleAssociation, "arrowhead=none");

		// Si un nom d'association a été stipulé
		if (associationName != null) {
			// Création de la propriété pour le nom de l'association
			this.addPropertyToAssociation(simpleAssociation, "label=\""
					+ associationName + "\"");
		}

		// Ajout de l'association au graphe;
		this.mGeneratedGraph.getAssociations().add(simpleAssociation);
	}

	/**
	 * Ajout une relation simple entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aLinkedClassName
	 *            , Nom de la Classe à lier
	 * @param associationName
	 *            , Nom de l'association (ou null).
	 */
	protected void addSimpleAssociationBetween(DotNode aClassNode,
			String aLinkedClassName, String associationName) {
		this.addSimpleAssociationBetween(aClassNode, new MetaClasse(
				aLinkedClassName), associationName);
	}

	/**
	 * Ajout une relation simple entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aLinkedClass
	 *            , Classe à lier
	 */
	protected void addSimpleAssociationBetween(DotNode aClassNode,
			MetaClasse aLinkedClass) {
		this.addSimpleAssociationBetween(aClassNode, aLinkedClass, null);
	}

	/**
	 * Ajout une relation simple entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aLinkedClassName
	 *            , Nom de la Classe à lier
	 */
	protected void addSimpleAssociationBetween(DotNode aClassNode,
			String aLinkedClassName) {
		this.addSimpleAssociationBetween(aClassNode, aLinkedClassName, null);
	}

	/**
	 * Ajoute une association d'aggrégation entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param anAssociatedClass
	 *            , Classe associée à lier.
	 * @param associationName
	 *            , Nom de l'association (ou null).
	 */
	protected void addAggregationAssociationBetween(DotNode aClassNode,
			MetaClasse anAssociatedClass, String associationName) {

		// Création de l'association entre la classe et sa classe associée
		DotAssociation associationAssociation = this.createAssociationBetween(
				aClassNode, anAssociatedClass);

		// Ajout du style de la fleche de l'association.
		this.addPropertyToAssociation(associationAssociation,
				"arrowhead=odiamond");

		// Si un nom d'association a été stipulé
		if (associationName != null) {
			// Création de la propriété pour le nom de l'association
			this.addPropertyToAssociation(associationAssociation, "label=\""
					+ associationName + "\"");
		}

		// Ajout de l'association au graphe;
		this.mGeneratedGraph.getAssociations().add(associationAssociation);
	}

	/**
	 * Ajoute une association d'aggrégation entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param anAssociatedClassName
	 *            , Nome de la Classe associée à lier.
	 * @param associationName
	 *            , Nom de l'association (ou null).
	 */
	protected void addAggregationAssociationBetween(DotNode aClassNode,
			String anAssociatedClassName, String associationName) {
		this.addAggregationAssociationBetween(aClassNode, new MetaClasse(
				anAssociatedClassName), associationName);
	}

	/**
	 * Ajoute une association d'aggrégation entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param anAssociatedClass
	 *            , Classe associée à lier.
	 */
	protected void addAggregationAssociationBetween(DotNode aClassNode,
			MetaClasse anAssociatedClass) {
		this.addAggregationAssociationBetween(aClassNode, anAssociatedClass,
				null);
	}

	/**
	 * Ajoute une association d'aggrégation entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param anAssociatedClassName
	 *            , Nome de la Classe associée à lier.
	 */
	protected void addAggregationAssociationBetween(DotNode aClassNode,
			String anAssociatedClassName) {
		this.addAggregationAssociationBetween(aClassNode,
				anAssociatedClassName, null);
	}

	/**
	 * Ajoute une relation de composition entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aCompositionClass
	 *            , Classe composée à lier
	 * @param associationName
	 *            , Nom de l'association (ou null).
	 */
	protected void addCompositionAssociationBetween(DotNode aClassNode,
			MetaClasse aCompositionClass, String associationName) {

		// Création de l'association entre la classe et sa super classe
		DotAssociation compositionAssociation = this.createAssociationBetween(
				aClassNode, aCompositionClass);

		// Ajout du style de la fleche de l'association.
		this.addPropertyToAssociation(compositionAssociation,
				"arrowhead=diamond");

		// Si un nom d'association a été stipulé
		if (associationName != null) {
			// Création de la propriété pour le nom de l'association
			this.addPropertyToAssociation(compositionAssociation, "label=\""
					+ associationName + "\"");
		}

		// Ajout de l'association au graphe;
		this.mGeneratedGraph.getAssociations().add(compositionAssociation);
	}

	/**
	 * Ajoute une relation de composition entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aCompositionClassName
	 *            , Nom de la Classe composée à lier
	 * @param associationName
	 *            , Nom de l'association (ou null).
	 */
	protected void addCompositionAssociationBetween(DotNode aClassNode,
			String aCompositionClassName, String associationName) {
		this.addCompositionAssociationBetween(aClassNode, new MetaClasse(
				aCompositionClassName), associationName);
	}

	/**
	 * Ajoute une relation de composition entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aCompositionClass
	 *            , Classe composée à lier
	 */
	protected void addCompositionAssociationBetween(DotNode aClassNode,
			MetaClasse aCompositionClass) {
		this.addCompositionAssociationBetween(aClassNode, aCompositionClass,
				null);
	}

	/**
	 * Ajoute une relation de composition entre deux Classes.
	 * 
	 * @param aClassNode
	 *            , Noeud DOT de la classe principale
	 * @param aCompositionClassName
	 *            , Nom de la Classe composée à lier
	 */
	protected void addCompositionAssociationBetween(DotNode aClassNode,
			String aCompositionClassName) {
		this.addCompositionAssociationBetween(aClassNode,
				aCompositionClassName, null);
	}

	/**
	 * Ajoute une association pour un héritage.
	 * 
	 * @param aSubClassifierNode
	 *            , Noeud DOT de la sous-classe
	 * @param aSuperClassifier
	 *            , SuperClasse ou SuperInterface à lier.
	 */
	protected void addExtendsAssociationBetween(DotNode aSubClassifierNode,
			MetaClassifier aSuperClassifier) {

		// Création d'une association inversée (pour avoir un affichage correct)
		DotAssociation extendsAssociation = this.createAssociationBetween(
				aSuperClassifier, aSubClassifierNode);

		// Ajout du style de la fleche de l'association.
		this.addPropertyToAssociation(extendsAssociation, "arrowhead=onormal");

		// Retournement de la fleche
		this.addPropertyToAssociation(extendsAssociation, "dir=back");

		// Ajout de l'association au graphe;
		this.mGeneratedGraph.getAssociations().add(extendsAssociation);
	}

	/**
	 * Ajoute une association pour l'implémentation d'une interface.
	 * 
	 * @param aClassNode
	 *            , Noeud de la classe implémentant l'interface.
	 * @param aMetaInterface
	 *            , Interface implémentée.
	 */
	protected void addImplementsAssociationBetween(DotNode aClassNode,
			MetaInterface aMetaInterface) {

		// Création d'une association inversée (pour avoir un affichage correct)
		DotAssociation implementsAssociation = this.createAssociationBetween(
				aMetaInterface, aClassNode);

		// Ajout du style de la fleche de l'association.
		this.addPropertyToAssociation(implementsAssociation, "style=dotted");
		this.addPropertyToAssociation(implementsAssociation,
				"arrowhead=onormal");

		// Retournement de la fleche
		this.addPropertyToAssociation(implementsAssociation, "dir=back");

		// Ajout de l'association au graphe;
		this.mGeneratedGraph.getAssociations().add(implementsAssociation);
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitClasse(lucava.metamodel.java.MetaClasse)
	 */
	@Override
	public void visitClasse(MetaClasse metaClasse) {

		// Création d'un noeud DOT pour la classe
		DotNode classeNode = new DotNode();
		classeNode.setName(metaClasse.getName());

		// Ajout de la propriété à la classe (i.e. ses composants internes)

		// Création d'un nouveau StringBuffer pour le contenu du composant
		this.mCurrentStringBuffer = new StringBuffer("style=filled,fillcolor=gray90,shape=record,");

		// Génération du contenu du composant
		this.generateClassContentComponent(metaClasse);

		// Ajout de la propriété au noeud
		DotProperty classProperty = new DotProperty();
		classProperty.setPropertyValue(this.mCurrentStringBuffer.toString());
		classeNode.getNodeProperties().add(classProperty);
		
		

		// Vidage du buffer d'écriture
		this.mCurrentStringBuffer = new StringBuffer();

		// Si une superClasse a été définie
		if (metaClasse.getExtends() != null) {
			// Ajout du lien entre la classe et sa superClasse
			this.addExtendsAssociationBetween(classeNode,
					metaClasse.getExtends());
		}

		// Ajout des éventuelles interfaces implémentées
		Iterator<MetaInterface> interfaceIt = metaClasse.getImplements()
				.iterator();
		while (interfaceIt.hasNext()) {
			// Ajout du lien entre la classe et l'interface implémentée
			this.addImplementsAssociationBetween(classeNode, interfaceIt.next());
		}

		// Ajout des éventuels liens (association/composition) des attributs de
		// la classe
		Iterator<Attribute> attributeIt = metaClasse.getAttributes().iterator();
		Attribute currentAttribute;
		while (attributeIt.hasNext()) {

			currentAttribute = attributeIt.next();

			// Récupération du type d'association
			String associationType = currentAttribute
					.getProperty("association");

			// Si l'association est une agrégation
			if (associationType == "aggregation") {

				// Ajout de la relation
				this.addAggregationAssociationBetween(classeNode,
						currentAttribute.getType().getName(),
						currentAttribute.getName());
			} else

			// Si l'association est une composition
			if (associationType == "composition") {
				// Ajout de la relation
				this.addCompositionAssociationBetween(classeNode,
						currentAttribute.getType().getName(),
						currentAttribute.getName());
			} else

			// Sinon, l'association est simple
			{
				// Ajout de la relation
				this.addSimpleAssociationBetween(classeNode, currentAttribute
						.getType().getName(), currentAttribute.getName());
			}
		}

		// Ajout de la classe au graphe généré
		this.mGeneratedGraph.getNodes().add(classeNode);
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitMethode(lucava.metamodel.java.Methode)
	 */
	@Override
	public void visitMethode(Methode metaMethode) {

		// Déport sur la signature de la méthode.
		metaMethode.getSignature().accept(this);
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitSignature(lucava.metamodel.java.MethodeSignature)
	 */
	@Override
	public void visitSignature(MethodeSignature metaSignature) {

		// Ajout de la visibilité de la signature
		metaSignature.getVisibility().accept(this);

		// Ajout du type de retour
		this.mCurrentStringBuffer.append(metaSignature.getReturnType()
				.getName() + " ");

		// Ajout du nom de la signature
		this.mCurrentStringBuffer.append(metaSignature.getName() + "(");

		// Ajout des paramètres de la signature
		Iterator<Parameter> parameterIt = metaSignature.getParams().iterator();
		while (parameterIt.hasNext()) {
			parameterIt.next().accept(this);

			// Ajout d'une virgule s'il reste des paramètres
			if (parameterIt.hasNext()) {
				this.mCurrentStringBuffer.append(", ");
			}
		}

		this.mCurrentStringBuffer.append(")");
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitVariable(lucava.metamodel.java.Variable)
	 */
	@Override
	public void visitVariable(Variable variable) {
		// Do nothing...
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitParametricType(lucava.metamodel.java.type.MetaParametricType)
	 */
	@Override
	public void visitParametricType(MetaParametricType metaParametricType) {
		// Do nothing

	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitMetaModel(lucava.metamodel.java.MetaModel)
	 */
	@Override
	public void visitMetaModel(MetaModel aMetaModel) {

		this.mGeneratedGraph = new DotGraph();
		this.getGeneratedGraph().setName(aMetaModel.getName());

		// Lancement de la visite de touts les classifiers du MetaModel
		Iterator<MetaClassifier> classifierIt = aMetaModel.getClassifier()
				.iterator();
		while (classifierIt.hasNext()) {
			classifierIt.next().accept(this);
		}
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitModifier(lucava.metamodel.java.Modifier)
	 */
	@Override
	public void visitModifier(Modifier modifier) {
		// Do nothing

	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitAnnotations(lucava.metamodel.java.Annotations)
	 */
	@Override
	public void visitAnnotations(Annotations annotations) {
		// Do nothing...
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitParameter(lucava.metamodel.java.Parameter)
	 */
	@Override
	public void visitParameter(Parameter parameter) {

		// Ajout du type du paramètre
		this.mCurrentStringBuffer.append(parameter.getType().getName() + " ");

		// Ajout du nom du paramètre
		this.mCurrentStringBuffer.append(parameter.getName());
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitMethodeBody(lucava.metamodel.java.MethodeBody)
	 */
	@Override
	public void visitMethodeBody(MethodeBody methodeBody) {
		// Do nothing...
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitComments(lucava.metamodel.java.Comments)
	 */
	@Override
	public void visitComments(Comments comments) {
		// TODO generate comment --

	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitPackage(lucava.metamodel.java.MetaPackage)
	 */
	@Override
	public void visitPackage(MetaPackage aPackage) {
		// Do nothing...
	}

	/**
	 * Suivre le lien.
	 * 
	 * @see lucava.metamodel.java.visitor.IJavaMetaModelVisitor#visitAttribute(lucava.metamodel.java.Attribute)
	 */
	@Override
	public void visitAttribute(Attribute attribute) {

		// Ajout de la visibilité de l'attribut
		attribute.getVisibility().accept(this);

		// Ajout du type de l'attribut
		this.mCurrentStringBuffer.append(attribute.getType().getName() + " ");

		// Ajout du nom de l'attribut
		this.mCurrentStringBuffer.append(attribute.getName());
	}

	/**
	 * Retourne le graphe DOT généré.
	 */
	public DotGraph getGeneratedGraph() {
		return mGeneratedGraph;
	}

}
